/*
 **	Query.h
 **
 **	Published / author: 2001-01-04 / grymse@telia.com
 **/
/*
Copyright (C) 2001 Anders Hedstrom

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#ifndef _QUERY_H
#define _QUERY_H
#ifndef _WIN32
// win32 project only, will not build on unix/linux
#include "fejk.h"
#endif

#include <string>
#include <map>

#ifdef ODBCW_NAMESPACE
namespace ODBCW_NAMESPACE {
#endif


// xml create options (method ReturnRowAsXML)
#define DQ_XML_ENDTAG 1
//#define DQ_XML_XMLWRAP 2 -- replaced by dq_xml_begin / _end...
#define DQ_XML_CDATASTRINGS 4
#define DQ_XML_TYPEINFO 8
#define DQ_XML_APPEND 16
#define DQ_XML_BEGIN 32
#define DQ_XML_END 64


// ODBC Catalog functions
// Use as only parameter with get_result()

#define SQLGET_CATALOGS 1
#define SQLGET_SCHEMAS 2
#define SQLGET_TABLES 3
#define SQLGET_TABLETYPES 4
#define SQLGET_COLUMNS 5
#define SQLGET_SPECIALCOLUMNS 6
#define SQLGET_PRIMARYKEYS 7
#define SQLGET_VIEWS 8


// ODBC length definitions
#define STR_LEN 128+1 // odbc
#define REM_LEN 254+1 // odbc
#define BUF_LEN 512 // DSQLHRES

/** this struct holds structural info for one result column */

typedef union
{
	bool b;
	char c;
	unsigned char byte;
	short s;
	int i; // not used
	long l;
	float f;
	double d;
	_int64 bigint;
	SQL_DATE_STRUCT date;
	SQL_TIME_STRUCT time;
	SQL_TIMESTAMP_STRUCT timestamp;
	SQL_NUMERIC_STRUCT numeric;
	SQLGUID guid;
	SQL_INTERVAL_STRUCT interval;
	char String[BUF_LEN];
} SQLUNIONBUFFER;


typedef struct sqlhcolstruct
{
	struct sqlhcolstruct *next;
	SQLCHAR szColumnName[STR_LEN];
	SQLSMALLINT nNameLengthPtr;
	char szTypeName[STR_LEN];
	SQLSMALLINT nDataTypePtr;
	SQLUINTEGER nColumnSizePtr;
	SQLSMALLINT nDecimalDigitsPtr;
	SQLSMALLINT nNullablePtr;
	SQLSMALLINT nCType;
	SQLUNIONBUFFER *buffer;
	SQLINTEGER cbBuffer;
	char *tmpstr;
} SQLHCOL;


class DSQLHRES
{
public:
	DSQLHRES(int); // number of cols to constructor
	~DSQLHRES();

	void add_col(SQLHCOL *);

	SQLSMALLINT m_num_cols;
	SQLHCOL **m_cols;

private:
	SQLHCOL *m_colbase;
	int m_qcols;
};



class Database;
class Session;

/** SQL Statement execute / result set helper class. */
class Query
{
public:
	/** Constructor accepting reference to database object. */
	Query(Database& dbin);
	/** Constructor accepting reference to database object
		and query to execute. */
	Query(Database& dbin,const std::string& sql);
	virtual ~Query();

	/** Check to see if database object is connectable. */
	bool Connected();
	/** Return reference to database object. */
	Database& GetDatabase() const;
	/** Return string of last query executed. */
	const std::string& GetLastQuery();

	/** Execute sql query that does not return a result. 
		\returns true if query is successful */
	short execute(const std::string& sql);

	/** execute query and store result. */
	bool get_result(const std::string& sql,char **attrs = NULL);

	/** free stored result, must be called after get_result() */
	void free_result();
	/** Fetch next result row.
		\return false if there was no row to fetch (end of rows) */
	bool fetch_row();
	/** Get id of last insert - not implemented. */
	long insert_id();
	/** Returns 0 if there are no rows to fetch. */
	long num_rows();
	/** Number of columns in current result. */
	int num_cols();
	/** Last error string. */
	const std::string& GetError();
	/** Last error code. */
	int GetErrno();

	/** Check if column x in current row is null. */
	bool is_null(int x);
	bool is_null(const std::string& x);
	bool is_null();

	/** Execute query and return first result as a string. */
	const char *get_string(const std::string& sql);
	/** Execute query and return first result as a long integer. */
	long get_count(const std::string& sql);
	/** Execute query and return first result as a double. */
	double get_num(const std::string& sql);

	const char *getstr(const std::string& x);
	/** Return value of column number x as a string value.
		\param x 0-based column index */
	const char *getstr(int x);
	const char *getstr();

	long getval(const std::string& x);
	/** Return value of column number x as a long integer.
		\param x 0-based column index */
	long getval(int x);
	long getval();

	_int64 getbigint(const std::string& x);
	/** Return value of column number x as a 64-bit integer.
		\param x 0-based column index */
	_int64 getbigint(int x);
	_int64 getbigint();

	double getnum(const std::string& x);
	/** Return value of column number x as a double.
		\param x 0-based column index */
	double getnum(int x);
	double getnum();

	/** ODBC Query specific */
	SQL_INTERVAL_STRUCT * getinterval(const std::string& x);
	SQL_INTERVAL_STRUCT * getinterval(int x);
	SQL_INTERVAL_STRUCT * getinterval();

	bool GetColumnInfo(short,SQLHCOL& );
	bool get_result(SQLSMALLINT func);
	bool get_result(SQLSMALLINT func, const std::string& catalog, const std::string& schema, const std::string& tablename);
	void ReturnRowAsXML(std::string& ,const std::string& = "",long = DQ_XML_ENDTAG);
	bool GotMore();
	bool getcol(std::string& colname,std::string& coltype,int& width,int& dec,int& nullable);
	bool getcol(int x,std::string& colname,std::string& coltype,int& width,int& dec,int& nullable);

private:
	bool odbc_store_result();
	void error(const std::string& text);
	//
	Database& m_db;
	Session *m_odb;
	SQLHSTMT m_hstmt; // %!
	DSQLHRES *m_hres;
	short m_currentcolumn; // colcount......... duh
	long m_results; // num_rows() after query
	long m_fetchrows; // 0..m_results-1
	int m_qcols; // number of columns in result
	int m_currentcol;
	std::string m_tmpstr;
	std::string m_last_query;
	std::string m_sql_state;
	std::string m_errtext;
	std::map<std::string,int> m_nmap;
};


#ifdef ODBCW_NAMESPACE
} // namespace ODBCW_NAMESPACE {
#endif
#endif // _QUERY_H
